/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package validadores.api;

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.JTextComponent;
import validadores.ValidadorFormato;

/**
 *
 *
 * Esta clase permite validar controles Swing que extiendan a la clase JTextComponent<br>
 * Estos pueden ser : <b>JEditorPane, JTextPane, JTextField</b><br>
 *
 */
public class ValidadorJTextComponent extends JLabel implements validadores.ValidadorComponent {

    private boolean obligatorio;
    private boolean valido;
    private JTextComponent componenteAValidar;
    private ValidarEn validarEn;
    private ValidadorFormato validadorFormato;
    private String mensajeError;

    /**
     * Costructor de la clase
     */
    public ValidadorJTextComponent() {
        setForeground(Color.red);
        setIcon(new javax.swing.ImageIcon(getClass().getResource(IconoValidador.SUGERENCIA.toString())));
        setText("");
        //this.setVisible(false);
    }

    /**
     * Este metodo permite configurar el metodo de validacion del campo<br>
     * Por defecto este metodo establece el campo como obligatorio, <br>
     * establece un mensaje de error en caso de vacio por defecto, <br>
     * establece el validador de formato a null y <br>
     * establece la validacion del campo como ON_CHANGE_AND_ON_FOCUS_LOST
     * @param componenteAValidar JTextcomponent a validar
     */
    public void configurarValidacion(JTextComponent componenteAValidar) {
        configurarValidacion(componenteAValidar,
                true,
                null,
                null,
                validarEn.ON_CHANGE_AND_ON_FOCUS_LOST);
    }

    /**
     * Este metodo permite configurar el metodo de validacion del campo,
     * ademas permite establecer si el campo es o no obligatorio.
     * Permite tambien establecer un mensaje personalizado de error en caso de estar vacio,
     * si no desea establecer el mensaje envie NULL, de esta manera aparecera un mensaje de error por defecto<br>
     * Por defecto este metodo establece
     * establece el validador de formato a null y <br>
     * establece la validacion del campo como ON_CHANGE_AND_ON_FOCUS_LOST
     * @param componenteAValidar JTextcomponent a validar
     * @param obligatorio true si es obligatorio, false si  no
     * @param mensajeErrorVacio String con el mensaje de error o NULL si desea un mensaje por defecto
     */
    public void configurarValidacion(JTextComponent componenteAValidar, boolean obligatorio,
            String mensajeErrorVacio) {
        configurarValidacion(componenteAValidar,
                obligatorio,
                mensajeErrorVacio,
                null,
                validarEn.ON_CHANGE_AND_ON_FOCUS_LOST);
    }

    /**
     * Este metodo permite configurar el metodo de validacion del campo,
     * ademas permite establecer si el campo es o no obligatorio.
     * Permite tambien establecer un mensaje personalizado de error en caso de estar vacio,
     * si no desea establecer el mensaje envie NULL, de esta manera aparecera un mensaje de error por defecto.
     * Ademas permite configurar un validador de formato<br>
     * Por defecto este metodo establece la validacion del campo como ON_CHANGE_AND_ON_FOCUS_LOST
     * @param componenteAValidar JTextcomponent a validar
     * @param obligatorio true si es obligatorio, false si  no
     * @param mensajeErrorVacio String con el mensaje de error o NULL si desea un mensaje por defecto
     * @param validadorFormato tipo de validacion a aplicar al texto del control
     */
    public void configurarValidacion(JTextComponent componenteAValidar, boolean obligatorio,
            String mensajeErrorVacio, ValidadorFormato validadorFormato) {
        configurarValidacion(componenteAValidar,
                obligatorio,
                mensajeErrorVacio,
                validadorFormato,
                validarEn.ON_CHANGE_AND_ON_FOCUS_LOST);
    }

    /**
     * Este metodo permite configurar el metodo de validacion del campo,
     * ademas permite establecer si el campo es o no obligatorio.
     * Permite tambien establecer un mensaje personalizado de error en caso de estar vacio,
     * si no desea establecer el mensaje envie NULL, de esta manera aparecera un mensaje de error por defecto.
     * Ademas permite configurar un validador de formato y el momento en que se desea validar<br>
     * @param componenteAValidar JTextcomponent a validar
     * @param obligatorio true si es obligatorio, false si  no
     * @param mensajeErrorVacio String con el mensaje de error o NULL si desea un mensaje por defecto
     * @param validadorFormato tipo de validacion a aplicar al texto del control
     * @param validarEn permite establecer en que momento se desea validar el control, los valores se encuentran en la enumeracion ValidarEn
     */
    public void configurarValidacion(JTextComponent componenteAValidar, boolean obligatorio,
            String mensajeErrorVacio, ValidadorFormato validadorFormato, ValidarEn validarEn) {
        setComponenteAValidar(componenteAValidar);
        setObligatorio(obligatorio);
        setMensajeError(mensajeErrorVacio);
        setValidadorFormato(validadorFormato);
        setValidarEn(validarEn);
        inicializarIcono();
    }

    public JComponent getComponenteAValidar() {
        return componenteAValidar;
    }

    /**
     * Establece el JTextComponent que debera validarse
     * @param componente
     */
    public void setComponenteAValidar(JTextComponent componente) {
        componenteAValidar = componente;
    }

    public void setComponenteAValidar(JComponent componente) {
        setComponenteAValidar((JTextComponent) componente);
    }

    public ValidadorFormato getValidadorFormato() {
        return validadorFormato;
    }

    public void setValidadorFormato(ValidadorFormato validador) {
        validadorFormato = validador;
    }

    public boolean isObligatorio() {
        return obligatorio;
    }

    public void setObligatorio(boolean obligatorio) {
        this.obligatorio = obligatorio;
    }

    public String getMensajeError() {
        String ret;
        if (mensajeError == null || mensajeError.isEmpty()) {
            ret = "Ingrese valor solicitado en el campo";
        } else {
            ret = mensajeError;
        }
        return ret;
    }

    public void setMensajeError(String mensaje) {
        mensajeError = mensaje;
    }

    public ValidarEn getValidarEn() {
        return validarEn;
    }

    public void setValidarEn(ValidarEn validaren) {
        validarEn = validaren;
        final ValidadorListener listener = new ValidadorListener();
        switch (getValidarEn()) {
            case ON_CHANGE:
                componenteAValidar.getDocument().addDocumentListener(listener);
                //componenteAValidar.setInputVerifier(listener);
                break;
            case ON_FOCUS_LOST:
                componenteAValidar.addFocusListener(listener);
                break;
            case ON_CHANGE_AND_ON_FOCUS_LOST:
                componenteAValidar.getDocument().addDocumentListener(listener);
                //componenteAValidar.setInputVerifier(listener);
                componenteAValidar.addFocusListener(listener);
                break;
        }
    }

    public boolean isValido() {
        return valido;
    }

    public void setValido(boolean valido) {
        this.valido = valido;
    }

    public boolean validar() {
        if (componenteEstaVacio()) {
            if (isObligatorio()) {
                //Si esta vacio y es obligatorio, entonces es error vacio
                cambiarInvalidoVacio();
            }else{
                //esta vacio pero como no es obligatorio, entonces es valido
                 cambiarValido();
            }
        } else {
            if (!(validadorFormato == null)) {
                //Si no esta vacio, validar formato
                if (validadorFormato.validar(componenteAValidar.getText())) {
                    //El formato es valido
                    cambiarValido();
                } else {
                    //el formato no es valido
                    cambiarInvalidoFormato();
                }
            } else {
                //No existe validador de formato, no esta vacio, asi que es valido
                cambiarValido();
            }
        }

        return isValido();
    }

    private void inicializarIcono() {
        setIcon(new javax.swing.ImageIcon(getClass().getResource(IconoValidador.SUGERENCIA.toString())));
        if (validadorFormato != null) {
            setText("");
            setToolTipText(validadorFormato.getSugerencia());
            //setText(validadorFormato.getSugerencia());
        } else {
           // setText("El valor de este campo es valido");
            setText("");
            setToolTipText("El valor de este campo es valido");
        }
    }

    private void cambiarValido() {
        setValido(true);
        componenteAValidar.setBackground(new Color(180, 240, 180));
        setIcon(new javax.swing.ImageIcon(getClass().getResource(IconoValidador.OK.toString())));
        if (validadorFormato != null) {
            setText("");
            setToolTipText(validadorFormato.getSugerencia());
            //setText(validadorFormato.getSugerencia());
        } else {
           // setText("El valor de este campo es valido");
            setText("");
            setToolTipText("El valor de este campo es valido");            
        }
    }

    private void cambiarInvalidoVacio() {
        setValido(false);
        componenteAValidar.setBackground(new Color(215, 94, 94));
        setIcon(new javax.swing.ImageIcon(getClass().getResource(IconoValidador.ERROR_VACIO.toString())));
        setText(this.getMensajeError());
    }

    private void cambiarInvalidoFormato() {
        setValido(false);
        componenteAValidar.setBackground(new Color(215, 94, 94));
        setIcon(new javax.swing.ImageIcon(getClass().getResource(IconoValidador.ERROR_FORMATO.toString())));
        if (validadorFormato != null) {
            setText(validadorFormato.getMensajeError());
        }else {
            setText("");
        }
    }

    /**
     * Este metodo determina si el texto del componente a validar esta vacio
     * @return true si esta vacio, false si no lo esta
     */
    boolean componenteEstaVacio() {
        boolean ret = true;
        if (!(componenteAValidar == null)) {//verificar que el control exista
            try {
                String texto = componenteAValidar.getText();//obtener el texto del control
                if (texto.isEmpty()) {
                    //el document existe, pero longitud es 0
                    ret = true;
                } else {
                    if (texto.trim().compareTo("") == 0) {
                        //contiene varios caracteres, pero todos son espacios
                        ret = true;
                    } else {
                        //no esta vacio
                        ret = false;
                    }
                }
            } catch (NullPointerException ex) {
                //si el document es null, entonces esta vacio
                ret = true;
            }
        } else {
            //el control no existe, no se puede verificar
            ret = true;
        }
        return ret;
    }



    class ValidadorListener implements DocumentListener, FocusListener, Runnable {

        public void focusLost(FocusEvent e) {
            validar();
        }

        public void focusGained(FocusEvent e) {
        }

        public void insertUpdate(DocumentEvent e) {
            removeUpdate(e);
        }

        public void removeUpdate(DocumentEvent e) {
            //Documents can be legally updated from another thread,
            //but we will not run validation outside the EDT
            if (!EventQueue.isDispatchThread()) {
                EventQueue.invokeLater(this);
            } else {
                validar();
            }
        }

        public void changedUpdate(DocumentEvent e) {
            removeUpdate(e);
        }

        public void run() {
            // validar();
        }

//        @Override
//        public boolean verify(JComponent input) {
//            return validar();
//        }
    }
}
